package cn.rokhdelar.ams.management.service.impl;

import cn.rokhdelar.ams.management.service.JwtService;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;

/**
 * Jwt服务实现类
 * @author Rokhdelar
 * @since 2024-10-02
 * @version 1.0.0
 */
@Service
@Slf4j
public class JwtServiceImpl implements JwtService {
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Integer expiration;

    /**
     * 生成Jwt Token
     *
     * @param userDetails sysUser对象
     * @return 返回jwt token
     */
    @Override
    public HashMap<String, Object> generateToken(UserDetails userDetails) {
        long current = System.currentTimeMillis();
        Date expirationDate = new Date(current + 1000L * 3600 * 24 * expiration);
        HashMap<String, Object> map = new HashMap<>();
        map.put("token","Bearer " +
                Jwts.builder()
                        .subject(userDetails.getUsername())
                        .issuedAt(new Date(System.currentTimeMillis()))
                        .expiration(expirationDate)
                        .signWith(getSigningKey()).compact());
        map.put("expirationDateTime", expirationDate);
        return map;
    }

    /**
     * 从token中获取用户名，用户名是以subject的方式放入token
     * @param token token字符串
     * @return 正常情况下，返回username，异常情况下返回null
     */
    @Override
    public String getUsername(String token) {
        return Jwts.parser()
                    .verifyWith(getSigningKey())
                    .build()
                    .parseSignedClaims(token)
                    .getPayload()
                    .getSubject();
    }

    /**
     * 判定Token是否有效，主要依据2个：一是用户名是否一致，二是token是否过期
     * @param token 需要判断的token
     * @param userDetails 对应的sysUser对象
     * @return 异常返回null，正常情况返回是否有效
     */
    @Override
    public Boolean isTokenValid(String token, UserDetails userDetails) {
        String username = Jwts.parser()
                    .verifyWith(getSigningKey())
                    .build()
                    .parseSignedClaims(token)
                    .getPayload()
                    .getSubject();

        return (username.equals(userDetails.getUsername()) && isTokenExpired(token));
    }
    /**
     * 判断Token是否过期
     * @param toke token字符串
     * @return 正常情况下，返回false，token过期时返回true
     */
    @Override
    public Boolean isTokenExpired(String toke) {
        Date expirationDate = Jwts.parser()
                .verifyWith(getSigningKey())
                .build()
                .parseSignedClaims(toke)
                .getPayload()
                .getExpiration();
        return !expirationDate.before(new Date());
    }

    /**
     * 根据密钥生成Key
     *
     * @return 返回生成的key对象
     */
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
    }

}
